package hikari.instruments.navmesh;

import com.gooddies.wiring.annotations.Wire;
import com.gooddies.wiring.annotations.WiringComponent;
import hikari.managers.EngineProperties;
import hikari.managers.Manager3D;
import java.awt.Cursor;
import java.util.LinkedList;
import java.util.Queue;
import org.swig.jirr.IMeshSceneNode;
import org.swig.jirr.ISceneNode;
import org.swig.jirr.SColor;
import org.swig.jirr.vector3df;

/**
 * @author Dmitry
 */
@WiringComponent
public class NavmeshAddTriangleInstrument extends NavmeshInstrument {

    private vector3df position;
    private ISceneNode sphere;
    private Queue<ISceneNode> selectedNodesQueue = new LinkedList<>();
    private boolean mousePointOnVertex = false;
    @Wire
    private EngineProperties engineProperties;
    @Wire
    private Manager3D manager3D;

    private NavmeshAddTriangleInstrument() {
    }

    private boolean isElementInQueue(ISceneNode node) {
        for (ISceneNode n : selectedNodesQueue) {
            if (n.hashCode() == node.hashCode()) {
                return true;
            }
        }

        return false;
    }

    private void pushToQueue(ISceneNode node) {
        if (isElementInQueue(node)) {
            selectedNodesQueue.remove(node);
        } else {
            selectedNodesQueue.add(node);
            if (selectedNodesQueue.size() > 2) {
                addTriangle();
                selectedNodesQueue.clear();
            }
        }
    }

    private void addTriangle() {
        ISceneNode[] nodes = selectedNodesQueue.toArray(new ISceneNode[0]);
        int[] indexesToAppend = new int[nodes.length];
        //S3DVertex[] meshVertexes = getMesh().getMeshSceneNode().getVertices();
        for (int i = 0; i < nodes.length; i++) {
            //S3DVertex vertex = getVertexByVertexSphere(nodes[i]);
            int index = getIndex(nodes[i]);
            if (index == -1) {
                return;
            }

            indexesToAppend[i] = index;
        }

        int[] lastIndexes = getMesh().getMeshSceneNode().getIndices();
        int[] newIndexes = utils.extendArray(lastIndexes, indexesToAppend);
        getMesh().getMeshSceneNode().setIndices(newIndexes);
        getMesh().getMeshSceneNode().recalculate();
    }

    @Override
    public void mouseDown(int x, int y, int button, int modifier) {
        super.mouseClick(x, y, button, modifier);
        if (isOnlyRightMouseDown(modifier)) {
            ISceneNode node = trySelect(x, y);
            if (node != null) {
                utils.setModified();
                pushToQueue(node);
            }
        } else if (isOnlyLeftMouseDown(modifier)) {
            if (!mousePointOnVertex) {
                utils.setModified();
                IMeshSceneNode vertexSphere = addVertex(position);
                addMeshSelectorToNode(vertexSphere);
            }
        }
    }

    @Override
    public void mouseMove(int x, int y, int dx, int dy, int modifier) {
        ISceneNode node = trySelect(x, y);
        position = calculatePositionOfPointer(x, y);
        if (node == null) {
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            mousePointOnVertex = false;
        } else {
            mousePointOnVertex = true;
            setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        }
        super.mouseMove(x, y, dx, dy, modifier);
    }

    @Override
    public void instrumentActivate() {

        sphere = createSphere(SColor.RED);
        sphere.setVisible(false);
        super.instrumentActivate();
        addMeshSelectorToAllSphereVertexes();
    }

    @Override
    public void instrumentDeactivate() {
        sphere.remove();
        super.instrumentDeactivate();
    }

    @Override
    public void onBeforeRender() {
        if (mousePointOnVertex) {
            sphere.setVisible(false);
        } else {
            if (position == null) {
                sphere.setVisible(false);
            } else {
                sphere.setPosition(position);
                sphere.setVisible(true);
            }
        }

        super.onBeforeRender();
    }

    @Override
    public void onAfterRenderBeforeGui() {
        super.onAfterRenderBeforeGui();
        ISceneNode[] selectedNodes = (ISceneNode[]) selectedNodesQueue.toArray(new ISceneNode[0]);
        manager3D.getVideoDriver().setMaterial(engineProperties.getSMaterialProperty("selectionBoxMaterial"));
        for (ISceneNode node : selectedNodes) {
            manager3D.getVideoDriver().draw3DBox(node.getTransformedBoundingBox());
        }
    }
}
